package ar.unc.famaf.pln.giveselector.loganalyser;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import ar.unc.famaf.pln.giveselector.builders.ACLBuilder;
import ar.unc.famaf.pln.giveselector.classifier.UtteranceP;
import ar.unc.famaf.pln.giveselector.context.Utterance;


/**
 * Unifies two or more serialized files into one.
 * Each serialized file must be a serialized Map<String, Set<Utterance>> object
 * which contains a database of annotated Utterances objects.
 *
 * @author David Racca ( david.racca@gmail.com )
 *
 */
public class Merger {

	private Map<String, Set<Utterance>> utterances;
	private static final String outputFile = "/datas/merged-action-utterances.bin.gz";


	/**
	 * Merges the given list of action-utterances serialized files
	 * into one.
	 */
	public static void main(String[] args)
	{
		Merger merger = new Merger();
		if (args.length == 0)
			System.out.println("You have to input the list of file names you want to merge.");
		else
		{
			for (int i=0; i<args.length; i++)
				merger.include(args[i]);
		}
		ACLBuilder.save(new File(outputFile), merger.getUtterances());
		System.out.println("Written output to: " + outputFile);
	}
	
	
	/**
	 * The Merger class constructor.
	 */
	public Merger()
	{
		utterances = new HashMap<String, Set<Utterance>>();
	}
	
	
	/**
	 * @return The merged map of Utterances.
	 */
	public Map<String, Set<Utterance>> getUtterances()
	{
		return utterances;
	}


	/**
	 * Adds all the Utterances objects contained in the given 
	 * serialized fileName to this Merger instance. 
	 * @param fileName
	 */
	protected void include(String fileName)
	{
		System.out.println("Merging file: " + fileName);
		Map<String, Set<Utterance>> utts = LogAnalyser.load(new File(fileName));

		if (utts != null)
		{
			if (utterances.isEmpty())
			{
				utterances = utts;
			}
			else
			{
				Iterator<String> keys = utts.keySet().iterator();
				while (keys.hasNext())
				{
					String worldName = keys.next();
					if (!utterances.containsKey(worldName))
						utterances.put(worldName, utts.get(worldName));
					else
						merge(worldName, utts.get(worldName));
				}
			}
		}
	}


	/**
	 * Merges the given set of Utterances objects with the internal
	 * set of Utterances associated with 'worldName' of this Merger instance.
	 */
	protected void merge(String worldName, Set<Utterance> utts1)
	{
		Iterator<Utterance> uit = utts1.iterator();
		Set<Utterance> utts2 = utterances.get(worldName);
		while (uit.hasNext())
		{
			Utterance utt1 = uit.next();
			Utterance utt2 = getUtteranceWithId(utt1.getId(), utts2);
			if (utt2 != null)
			{
				if (utt2 instanceof UtteranceP)
				{
					if (utt1 instanceof UtteranceP)
						((UtteranceP) utt2).addOccurrences(((UtteranceP) utt1).getOccurrences());
				}
				else if (utt1 instanceof UtteranceP)
				{
					utts2.remove(utt2);
					utts2.add(utt1);
				}
			}
			else
				utterances.get(worldName).add(utt1);
		}
	}


	/**
	 * @return The Utterance from the given Set with the
	 * given id. Null if there are not such object in the Set
	 */
	public static Utterance getUtteranceWithId(int id, Set<Utterance> utts)
	{
		Utterance u = null;
		Iterator<Utterance> it = utts.iterator();

		while (it.hasNext())
		{
			u = it.next();
			if (u.getId() == id)
				return u;
		}
		return u;
	}

}
